package process;

import java.util.Random;

import device.DeviceManage;
import javafx.application.Platform;
import memory.*;

public class CPU implements Runnable {
	private int pc; // 程序计数器
	private int ax = 0; // 主要寄存器
	private boolean hangOutFlag = true;

	// 程序状态字
	private int psw_process_end = 0;// 程序结束end
	private int psw_clock_end = 0;// 时钟中断
	private int psw_io = 0; // I/O设备中断
							// 程序状态字

	private int ir; // 指令寄存器 （类型未定）
	private PCB pcb = PCBData.getHangOutPcb(); // 储存当期程序的进程控制快

	private int systemTime = 0;// 系统时间
	private int relativeTime = 0;// 相对时间
	public static final int TIME_SLICE = 6;// 时间片
	private int nextCreateTime = 1;// 下一次随机创建进程的时间

	// 单例模式
	private static CPU cpu;

	public static CPU getCpu() {
		if (cpu == null) {
			cpu = new CPU();
			cpu.setHangOutFlag(true);
		}

		return cpu;
	}

	@Override
	public void run() {
		while (true) {
			/*if(PCBData.readyList.size()==0)
				hangOutFlag=true;
			else hangOutFlag=false;*/
			systemTime++;// 时钟跳动
			
			DeviceManage.reduceAllTime();// 设备时间减少

			if (hangOutFlag) {// 创建闲逛进程
				pcb = PCBData.getHangOutPcb();
				readPcb();
				hangOutFlag = false;
			}

			// 中断检测
			if (interruptDetect()) {
				refreshUI();
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				continue;
			}
			//
			excuteInstruction();// 执行命令
			// nextCreateProcess();// 下一次随机创建进程的时间时间检测

			relativeTime--;// 相对时间减少

			Platform.runLater(()->{
				ProcessController.getProcessController().setShowFlag();// 改变时钟图标
			});
			refreshUI();

			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	// 中断检测
	public boolean interruptDetect() {
		// 程序结束
		if (this.psw_process_end == 1) {
			ProcessController.getProcessController().outPut("进程" + pcb.getPid() + "结束\n");
			destroy();
			if (choosePcb())
				readPcb();
			return true;
		}
		// 时间片结束
		if (this.relativeTime == 0) { // 相对时间为0时时钟中断
			savePcb();
			if (choosePcb())
				readPcb();
			return true;
		}
		//  I/O中断
		if (PCBData.blockQueue.size() > 0) {
			int size = DeviceManage.canRelease();
			System.out.println("size"+PCBData.blockQueue.size());
			if (size > 0) {
				int[] pids = DeviceManage.getTimeoutPid(size);
				for (int pid : pids) {
					char type = DeviceManage.releaseDevice(pid);
					int index = PCBData.blockPCBIndex(pid);
					if (index > -1) {
						awake(PCBData.blockQueue.get(index));
					}
					index=PCBData.searchWait(type);
					if (index > -1) {
						awake(PCBData.blockQueue.get(index));
					}
				}
			}
			if(size>0)
				return true;
		}
		return false;
	}

	// 检查随机创建新进程的时间是否到达，到达则创建新进程并给予下一次创建的时间
//	public void nextCreateProcess() {
//		if (systemTime == nextCreateTime) {
//			// 创建新进程
//			nextCreateTime += (5 + (new Random()).nextInt(10));// 增加随机时间用于下次创建
//			System.out.println("创建了一个随机进程，下次创建时间为：" + nextCreateTime);
//		}
//	}

	// 保存PCB
	public void savePcb() {
		this.pcb.setAx(ax);
		this.pcb.setPc(pc);
		this.pcb.setPsw_io(psw_io);
		this.pcb.setPsw_process_end(psw_process_end);
		PCBData.readyList.add(pcb);// 放置在就绪队列尾部
		// hangOutFlag = true;
	}

	// 选择一个进程
	public boolean choosePcb() { // 如果队列中有进程则返回true
		if (PCBData.readyList.size() > 0) {
			this.pcb = PCBData.readyList.remove(0);// 从就绪队列取出一个pcb
			hangOutFlag = false;
			return true;
		} else {
			hangOutFlag = true;
			return false;
		}
	}

	// 恢复PCB
	public void readPcb() {
		this.ax = this.pcb.getAx();
		this.pc = this.pcb.getPc();
		this.psw_process_end = pcb.getPsw_process_end();
		this.psw_io = pcb.getPsw_io();
		this.relativeTime = TIME_SLICE;
		ProcessController.getProcessController().outPut("读取进程 " + pcb.getPid() + "\n");
	}

	public boolean create(String str) {
		// TODO 申请空白进程控制块；		

		PCB newPcb = PCB.register(str.length());
		// TODO 申请主存空间， 申请成功， 装入主存；
		if(newPcb!=null) {
			newPcb.setProcess(new Process(str));
			ProcessController.getProcessController().outPut("进程 "+ newPcb.getPid()+" 创建成功\n");
			return true;
		}
		else {
			ProcessController.getProcessController().outPut("内存空间不足！！！创建进程失败\n");
			return false;
		}
		// TODO 初始化进程控制块；
		// TODO 修改hangOutFlag;
		// TODO 在屏幕上显示进程执行结果， 进程撤销。
	}

	public void destroy() {
		//  在屏幕上显示进程执行结果， 进程撤销。
		ProcessController.getProcessController().outPut("摧毁进程 " + pcb.getPid() + "\n");
		PCB.delete(pcb.getPid());
		pcb = null;
	}

	// 收到阻塞请求
	public void block() {
		savePcb();
		// TODO 修改进程状态；
		// TODO 将进程链入对应的阻塞队列， 然后转向进程调度。
		ProcessController.getProcessController().outPut("进程 " + pcb.getPid() + "进 入阻塞队列\n");
		PCBData.blockQueue.add(pcb);
		choosePcb();
		readPcb();
	}

	// TODO 将进程由阻塞队列中摘下， 修改进程状态为就绪， 然后链入就绪队列。
	public void awake(PCB pcb) {
		pcb.setPsw_io(0);
		pcb.setType('?');
		PCBData.readyList.add(pcb);
		PCBData.blockQueue.remove(pcb);
	}

	private void excuteInstruction() {// 执行当前进程中的命令
		pcb.getProcess().excuteInstruction(pc);
		pc++;
	}

	private void refreshUI() {
		Platform.runLater(() -> {
			ProcessController.getProcessController().refresh();
		});
	}

	// Setters and Getters
	public int getPc() {
		return pc;
	}

	public void setPc(int pc) {
		this.pc = pc;
	}

	public int getAx() {
		return ax;
	}

	public void setAx(int ax) {
		this.ax = ax;
	}

	public int getPsw_process_end() {
		return psw_process_end;
	}

	public void setPsw_process_end(int psw_process_end) {
		this.psw_process_end = psw_process_end;
	}

	public int getPsw_clock_end() {
		return psw_clock_end;
	}

	public void setPsw_clock_end(int psw_clock_end) {
		this.psw_clock_end = psw_clock_end;
	}

	public int getPsw_io() {
		return psw_io;
	}

	public void setPsw_io(int psw_io) {
		this.psw_io = psw_io;
	}

	public int getIr() {
		return ir;
	}

	public void setIr(int ir) {
		this.ir = ir;
	}
	
	public PCB getPcb() {
		return pcb;
	}

	public void setPcb(PCB pcb) {
		this.pcb = pcb;
	}

	public int getSystemTime() {
		return systemTime;
	}

	public int getRelativeTime() {
		return relativeTime;
	}

	public int getNextCreateTime() {
		return nextCreateTime;
	}

	public boolean isHangOutFlag() {
		return hangOutFlag;
	}

	public void setHangOutFlag(boolean hangOutFlag) {
		this.hangOutFlag = hangOutFlag;
	}

}
